﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Windows.Forms;
using System.Collections;
using Microsoft.Xna.Framework;

namespace FeedAntGame.Support
{
    class Database
    {
        protected static XmlElement Data;
        protected static XmlNodeList HienTrang;
        protected static XmlNodeList HScore;
        protected static XmlNodeList BanDo;
        protected static int numOfRank = 5;

        public static void InitDatabase()
        {
            if (File.Exists(Application.StartupPath + @"\DB.xml"))
            {
                Data = XL_XML.Read_Root("DB.xml");
                HienTrang = Data.SelectNodes("//HIEN_TRANG");
                HScore = Data.SelectNodes("//HIGH_SCORE");
                BanDo = Data.SelectNodes("//MAP");
            }
            else//Chua co file
            {
                Data = XL_XML.Tao_Goc("GAME");
                //Init HIEN_TRANG
                XmlElement ht =  XL_XML.Tao_Nut_Con(Data, "HIEN_TRANG");
                ht.SetAttribute("Level", "1");
                ht.SetAttribute("Score", "0");
                XL_XML.Ghi_Nut(Data, "DB.xml");
                RefreshDatabase();
            }
        }

        private static void RefreshDatabase()
        {
            HienTrang = Data.SelectNodes("//HIEN_TRANG");
            HScore = Data.SelectNodes("//HIGH_SCORE");
            BanDo = Data.SelectNodes("//MAP");
        }

        public static int _MaxRank
        {
            set
            {
                numOfRank = value;
            }
        }

        public static class Hien_Trang
        {
            //Lay hien trang duoc luu gan day nhat(luu sau cung)
            public static int _RecentLevel
            {
                get
                {
                    if (HienTrang != null && HienTrang.Count != 0)
                    {
                        return Int32.Parse(((XmlElement)HienTrang[HienTrang.Count - 1]).GetAttribute("Level"));
                    }
                    else
                        return 0;
                }
            }

            public static int _RecentScore
            {
                get
                {
                    if (HienTrang != null && HienTrang.Count != 0)
                    {
                        return Int32.Parse(((XmlElement)HienTrang[HienTrang.Count - 1]).GetAttribute("Score"));
                    }
                    else
                        return 0;
                }
            }

            //Luu tinh trang hien tai
            public static void LuuHienTrang(int Level, int Score)
            {
                XmlElement ht = null;
                if (HienTrang == null)
                {
                    ht = XL_XML.Tao_Nut_Con(Data, "HIEN_TRANG");
                }
                else
                {
                    ht = (XmlElement)HienTrang[0];
                }
                ht.SetAttribute("Level", Level.ToString());
                if (Level == 1)
                {
                    Score = 0;
                }
                ht.SetAttribute("Score", Score.ToString());
                XL_XML.Ghi_Nut(Data, "DB.xml");
                RefreshDatabase();
            }

            //Lay ra tinh trang da luu nhat dinh
            /// <summary>
            /// Array int contains two member. First : Level, Second : Score. If Array int count = 0 => Should play new game
            /// </summary>
            /// <returns></returns>
            public static int[] LayHienTrang()
            {
                if (HienTrang == null)
                    return new int[0];
                int[] ht = new int[2];
                XmlElement recent = (XmlElement)HienTrang[0];
                ht[0] = Int32.Parse(recent.GetAttribute("Level"));
                ht[1] = Int32.Parse(recent.GetAttribute("Score"));
                return ht;
            }
        }

        public static class HighScore
        {
            /// <summary>
            /// Return list of array list : rank , player , level, score
            /// </summary>
            /// <returns></returns>
            public static List<ArrayList> GetAllRank()
            {
                if (HScore == null)
                    return null;
                List<ArrayList> highscore = new List<ArrayList>();
                for (int i = 0; i < HScore.Count; i++)
                {
                    XmlElement rank = (XmlElement)HScore[i];
                    ArrayList r = new ArrayList();
                    r.Add(rank.GetAttribute("Rank"));
                    r.Add(rank.GetAttribute("Player"));
                    r.Add(rank.GetAttribute("Level"));
                    r.Add(rank.GetAttribute("Score"));
                    highscore.Add(r);
                }

                return highscore;
            }

            public static int[] GetAllHighScore()
            {
                if (HScore.Count == 0 || HScore == null)
                    return new int[0];
                else
                {
                    int[] score = new int[HScore.Count];
                    for (int i = 0; i < HScore.Count; i++)
                    {
                        XmlElement hsTemp = (XmlElement)HScore[i];
                        score[i] = Int32.Parse(hsTemp.GetAttribute("Score"));
                    }
                    return score;
                }
            }

            public static bool CheckAndSaveHighScore(int score, int Level, String Player)
            {
                bool result = false;
                int max_score = int.MinValue;
                int min_rank = int.MaxValue;
                int[] hscore = GetAllHighScore();
                int i = 0;
                XmlElement hs;
                
                if (hscore.Count() == 0)
                {
                    // rong
                    hs = XL_XML.Tao_Nut_Con(Data, "HIGH_SCORE");
                    hs.SetAttribute("Rank", (1).ToString());
                }
                else 
                {
                    
                    for (i = 0; i < hscore.Count(); i++)
                    {
                        XmlElement hsTemp = (XmlElement)HScore[i];
                        int tempRank = Int32.Parse(hsTemp.GetAttribute("Rank"));
                        if (score > hscore[i] && tempRank < min_rank && score >= max_score)
                        {
                            min_rank = tempRank;
                            max_score = score;
                        }
                    }

                    for (int j = 0; j < hscore.Count(); j++)
                    {
                        // increase rank to which element have rank >= min_rank
                        XmlElement hsTemp = (XmlElement)HScore[j];
                        int tempRank = Int32.Parse(hsTemp.GetAttribute("Rank"));
                        if (tempRank >= min_rank)
                        {
                            hsTemp.SetAttribute("Rank", (tempRank + 1).ToString());
                        }
                    }

                    if (hscore.Count() < Database.numOfRank)
                    {
                        // co' ma thieu
                        hs = XL_XML.Tao_Nut_Con(Data, "HIGH_SCORE");
                        if(min_rank == int.MaxValue)
                            min_rank = hscore.Count() + 1;
                        hs.SetAttribute("Rank", (min_rank).ToString());
                    }
                    else
                    {
                        // full
                        int max_rank = int.MinValue;
                        int chosen = 0;
                        for (int j = 0; j < hscore.Count(); j++)
                        {
                            // increase rank to which element have rank >= min_rank
                            XmlElement hsTemp = (XmlElement)HScore[j];
                            int tempRank = Int32.Parse(hsTemp.GetAttribute("Rank"));
                            if (tempRank > max_rank)
                            {
                                max_rank = tempRank;
                                chosen = j;
                            }
                        }
                        hs = (XmlElement)HScore[chosen];
                        if (min_rank != int.MaxValue)
                        {
                            hs.SetAttribute("Rank", (min_rank).ToString());
                        }
                        else
                        {
                            return result;
                        }
                        
                    }                   
                    
                }               
                    
                hs.SetAttribute("Player", Player);
                hs.SetAttribute("Level", Level.ToString());
                hs.SetAttribute("Score", score.ToString());
                XL_XML.Ghi_Nut(Data, "DB.xml");
                RefreshDatabase();

                result = true;
                return result;
            }
        }

        public static class Map
        {
            /// <summary>
            /// ArrayList: mapName, imagePath, barrier position[], barrier type[], destination position[], destination type[], 
            /// danger position[], danger type[], ant position[], ant type[]
            /// </summary>
            /// <returns></returns>
            public static ArrayList GetMap(string name)
            {
                if (BanDo == null)
                    return null;
                for (int i = 0; i < BanDo.Count; i++)
                {
                    XmlElement m = (XmlElement)BanDo[i];
                    if (m.GetAttribute("Name") == name)
                    {
                        ArrayList maplist = new ArrayList();
                        maplist.Add(m.GetAttribute("Name"));
                        maplist.Add(m.GetAttribute("ImagePath"));
                        XmlNodeList barrier = m.SelectNodes("//BARRIER");
                        XmlNodeList destination = m.SelectNodes("//DESTINATION");
                        XmlNodeList danger = m.SelectNodes("//DANGER");
                        XmlNodeList ant = m.SelectNodes("//ANT");
                        Point[] barrierPos = new Point[barrier.Count];
                        String[] barrierType = new String[barrier.Count];
                        Point[] desPos = new Point[destination.Count];
                        String[] desType = new String[destination.Count];
                        Point[] dangerPos = new Point[danger.Count];
                        String[] dangerType = new String[danger.Count];
                        Point[] antPos = new Point[ant.Count];
                        String[] antType = new String[ant.Count];
                        for (int j = 0; j < barrier.Count; j++)
                        {
                            barrierPos[j].X = Int32.Parse(((XmlElement)barrier[j]).GetAttribute("X"));
                            barrierPos[j].Y = Int32.Parse(((XmlElement)barrier[j]).GetAttribute("Y"));
                            barrierType[j] = ((XmlElement)barrier[j]).GetAttribute("TYPE").ToString();
                        }
                        for (int j = 0; j < destination.Count; j++)
                        {
                            desPos[j].X = Int32.Parse(((XmlElement)destination[j]).GetAttribute("X"));
                            desPos[j].Y = Int32.Parse(((XmlElement)destination[j]).GetAttribute("Y"));
                            desType[j] = ((XmlElement)barrier[j]).GetAttribute("TYPE").ToString();
                        }
                        for (int j = 0; j < danger.Count; j++)
                        {
                            dangerPos[j].X = Int32.Parse(((XmlElement)danger[j]).GetAttribute("X"));
                            dangerPos[j].Y = Int32.Parse(((XmlElement)danger[j]).GetAttribute("Y"));
                            dangerType[j] = ((XmlElement)barrier[j]).GetAttribute("TYPE").ToString();
                        }
                        for (int j = 0; j < ant.Count; j++)
                        {
                            antPos[j].X = Int32.Parse(((XmlElement)ant[j]).GetAttribute("X"));
                            antPos[j].Y = Int32.Parse(((XmlElement)ant[j]).GetAttribute("Y"));
                            antType[j] = ((XmlElement)ant[j]).GetAttribute("TYPE").ToString();
                        }
                        maplist.Add(barrierPos);
                        maplist.Add(barrierType);
                        maplist.Add(desPos);
                        maplist.Add(desType);
                        maplist.Add(dangerPos);
                        maplist.Add(dangerType);
                        maplist.Add(antPos);
                        maplist.Add(antType);
                        return maplist;
                    }                    
                }
                return null;
            }
            /// <summary>
            /// List of arrayList: mapName, imagePath, barrier position[], barrier type[], destination position[], destination type[], 
            /// danger position[], danger type[], ant position[], ant type[]
            /// </summary>
            /// <returns></returns>
            public static List<ArrayList> GetAllMap()
            {
                if (BanDo == null)
                    return null;
                List<ArrayList> map = new List<ArrayList>();
                for (int i = 0; i < BanDo.Count; i++)
                {
                    XmlElement m = (XmlElement)BanDo[i];
                    ArrayList maplist = new ArrayList();
                    maplist.Add(m.GetAttribute("Name"));
                    maplist.Add(m.GetAttribute("ImagePath"));
                    XmlNodeList barrier = m.SelectNodes("//BARRIER");
                    XmlNodeList destination = m.SelectNodes("//DESTINATION");
                    XmlNodeList danger = m.SelectNodes("//DANGER");
                    XmlNodeList ant = m.SelectNodes("//ANT");
                    Point[] barrierPos = new Point[barrier.Count];
                    String[] barrierType = new String[barrier.Count];
                    Point[] desPos = new Point[destination.Count];
                    String[] desType = new String[destination.Count];
                    Point[] dangerPos = new Point[danger.Count];
                    String[] dangerType = new String[danger.Count];
                    Point[] antPos = new Point[ant.Count];
                    String[] antType = new String[ant.Count];
                    for (int j = 0; j < barrier.Count; j++)
                    {
                        barrierPos[j].X = Int32.Parse(((XmlElement)barrier[j]).GetAttribute("X"));
                        barrierPos[j].Y = Int32.Parse(((XmlElement)barrier[j]).GetAttribute("Y"));
                        barrierType[j] = ((XmlElement)barrier[j]).GetAttribute("TYPE").ToString();
                    }
                    for (int j = 0; j < destination.Count; j++)
                    {
                        desPos[j].X = Int32.Parse(((XmlElement)destination[j]).GetAttribute("X"));
                        desPos[j].Y = Int32.Parse(((XmlElement)destination[j]).GetAttribute("Y"));
                        desType[j] = ((XmlElement)barrier[j]).GetAttribute("TYPE").ToString();
                    }
                    for (int j = 0; j < danger.Count; j++)
                    {
                        dangerPos[j].X = Int32.Parse(((XmlElement)danger[j]).GetAttribute("X"));
                        dangerPos[j].Y = Int32.Parse(((XmlElement)danger[j]).GetAttribute("Y"));
                        dangerType[j] = ((XmlElement)barrier[j]).GetAttribute("TYPE").ToString();
                    }
                    for (int j = 0; j < ant.Count; j++)
                    {
                        antPos[j].X = Int32.Parse(((XmlElement)ant[j]).GetAttribute("X"));
                        antPos[j].Y = Int32.Parse(((XmlElement)ant[j]).GetAttribute("Y"));
                        antType[j] = ((XmlElement)ant[j]).GetAttribute("TYPE").ToString();
                    }
                    maplist.Add(barrierPos);
                    maplist.Add(barrierType);                    
                    maplist.Add(desPos);
                    maplist.Add(desType);
                    maplist.Add(dangerPos);
                    maplist.Add(dangerType);
                    maplist.Add(antPos);
                    maplist.Add(antType);
                    //code here to get more attribute
                    map.Add(maplist);
                }
                return map;
            }

            private static bool CheckNameValid(String name)
            {
                XmlElement nameSelect = (XmlElement)Data.SelectSingleNode("//MAP[@Name = '" + name + "']");
                if (nameSelect != null)
                    return false;
                else
                    return true;
            }

            public static bool LuuMap(String name, String ImagePath, Point[] bPos, String[] bType, Point[] dPos, String[] dType,
                Point[] dangerPos, String[] dangerType, Point[] aPos, String[] aType)
            {
                if (!CheckNameValid(name))
                {
                    return false;
                }
                XmlElement map = XL_XML.Tao_Nut_Con(Data, "MAP");
                map.SetAttribute("Name", name);
                map.SetAttribute("ImagePath", ImagePath);
                for (int i = 0; i < bPos.Count(); i++)
                {
                    XmlElement Pos = XL_XML.Tao_Nut_Con(map, "BARRIER");
                    Pos.SetAttribute("X", bPos[i].X.ToString());
                    Pos.SetAttribute("Y", bPos[i].Y.ToString());
                    Pos.SetAttribute("TYPE", bType[i]);
                }
                for (int i = 0; i < dPos.Count(); i++)
                {
                    XmlElement Pos = XL_XML.Tao_Nut_Con(map, "DESTINATION");
                    Pos.SetAttribute("X", dPos[i].X.ToString());
                    Pos.SetAttribute("Y", dPos[i].Y.ToString());
                    Pos.SetAttribute("TYPE", dType[i]);
                }
                for (int i = 0; i < dangerPos.Count(); i++)
                {
                    XmlElement Pos = XL_XML.Tao_Nut_Con(map, "DANGER");
                    Pos.SetAttribute("X", dangerPos[i].X.ToString());
                    Pos.SetAttribute("Y", dangerPos[i].Y.ToString());
                    Pos.SetAttribute("TYPE", dangerType[i]);
                }
                for (int i = 0; i < aPos.Count(); i++)
                {
                    XmlElement Pos = XL_XML.Tao_Nut_Con(map, "ANT");
                    Pos.SetAttribute("X", aPos[i].X.ToString());
                    Pos.SetAttribute("Y", aPos[i].Y.ToString());
                    Pos.SetAttribute("TYPE", aType[i]);
                }
                XL_XML.Ghi_Nut(Data, "DB.xml");
                RefreshDatabase();
                return true;
            }

            public static bool XoaMap(String name)
            {
                XmlElement selectmap = (XmlElement)Data.SelectSingleNode("//MAP[@Name = '" + name + "']");
                if (selectmap != null)
                {
                    selectmap.ParentNode.RemoveChild(selectmap);
                    RefreshDatabase();
                    return true;
                }
                else
                    return false;
            }
        }
    }
}